import subprocess
from pathlib import Path

import magic
from openpyxl import load_workbook


class XLS2XLSX:
    LIBREOFFICE_PATH = "D:/LibreOffice/program/soffice.exe"

    def __init__(self, file_path: Path):
        self.file_path = file_path
        with open(file_path, "rb") as f:
            self.file_type = magic.from_buffer(f.read(2048), mime=True)
        if not self.file_type:
            raise ValueError(f"Could not determine file type for {file_path}")

    def output_xlsx(self):
        """Convert the input file to .xlsx format if needed and return the new path."""
        # Handle CDF (Compound Document Format) - typical of .xls files
        if self.file_type in ["application/CDFV2", "application/cdfv2-corrupt"] or \
           self.file_type.startswith("Composite Document File V2 Document"):
            return self._xls_to_xlsx_by_libreoffice()

        # .xlsx files in a zip container (e.g., some .xlsx may be detected as zip)
        elif self.file_type == "application/zip":
            new_path = self.file_path.with_suffix(".xlsx")
            self.file_path.rename(new_path)
            return new_path

        # Legacy Excel format (.xls)
        elif self.file_type == "application/vnd.ms-excel":
            try:
                load_workbook(self.file_path)
                return self.file_path  # Already valid .xlsx or readable .xls
            except Exception:
                return self._xls_to_xlsx_by_libreoffice()

        # Already a modern .xlsx file
        elif self.file_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
            return self.file_path

        else:
            raise ValueError(f"Unsupported file type: {self.file_type}")

    def _xls_to_xlsx_by_libreoffice(self):
        """Use LibreOffice CLI to convert .xls to .xlsx."""
        out_dir = self.file_path.parent
        command = [
            XLS2XLSX.LIBREOFFICE_PATH,
            "--headless",
            "--convert-to", "xlsx:Calc MS Excel 2007 XML",
            "--outdir", str(out_dir),
            str(self.file_path)
        ]

        try:
            subprocess.run(
                command,
                check=True,
                capture_output=True,
                text=True,
                encoding="utf-8",
                errors="ignore"
            )
            # On success, LibreOffice outputs {stem}.xlsx in out_dir
            return out_dir / f"{self.file_path.stem}.xlsx"

        except subprocess.CalledProcessError as e:
            raise RuntimeError(
                f"LibreOffice conversion failed for {self.file_path}. "
                f"Exit code: {e.returncode}. Command: {' '.join(e.cmd)}"
            ) from e

        except FileNotFoundError:
            raise FileNotFoundError(
                f"LibreOffice not found at path: {XLS2XLSX.LIBREOFFICE_PATH}. "
                "Please check the LIBREOFFICE_PATH configuration."
            )


